package com.system.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 *
 *         <dependency>
 *             <groupId>org.apache.commons</groupId>
 *             <artifactId>commons-lang3</artifactId>
 *         </dependency>
 *
 *         <dependency>
 *             <groupId>com.alibaba</groupId>
 *             <artifactId>easyexcel</artifactId>
 *             <version>4.0.3</version>
 *         </dependency>
 *
 *
 */
public class ExcelUtil {

    /**
     * 将列表以 Excel 响应给前端
     *
     * @param response  响应
     * @param filename  文件名
     * @param sheetName Excel sheet 名
     * @param head      Excel head 头
     * @param data      数据列表哦
     * @param <T>       泛型，保证 head 和 data 类型的一致性
     * @throws IOException 写入失败的情况
     */
    public static <T> void write(HttpServletResponse response, String filename, String sheetName,
                                 Class<T> head, List<T> data) throws IOException {
        // 输出 Excel
        EasyExcel.write(response.getOutputStream(), head)
                .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度，自动适配。最大 255 宽度
                .sheet(sheetName).doWrite(data);
        // 设置 header 和 contentType。写在最后的原因是，避免报错时，响应 contentType 已经被修改了
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    }


    /**
     * 将列表以 Excel 响应给前端
     *
     * @param response  响应
     * @param filename  文件名
     * @param sheetName Excel sheet 名
     * @param head      Excel head 头
     * @param data      数据列表哦
     * @param <T>       泛型，保证 head 和 data 类型的一致性
     * @throws IOException 写入失败的情况
     */
    public static <T> void write(HttpServletResponse response, String filename, String sheetName,
                                 List<List<String>> head, List<T> data) throws IOException {
        // 输出 Excel
        EasyExcel.write(response.getOutputStream()).head(head)
                .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度，自动适配。最大 255 宽度
                .sheet(sheetName).doWrite(data);
        // 设置 header 和 contentType。写在最后的原因是，避免报错时，响应 contentType 已经被修改了
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    }


    /**
     * 读取 MultipartFile 文件
     *
     * @param file
     * @param head
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
        return EasyExcel.read(file.getInputStream(), head, null)
                .autoCloseStream(false)  // 不要自动关闭，交给 Servlet 自己处理
                .doReadAllSync();
    }


    public static <T> List<T> read(InputStream inputStream, Class<T> head) throws IOException {
        return EasyExcel.read(inputStream, head, null)
                .autoCloseStream(true)  // 不要自动关闭，交给 Servlet 自己处理
                .doReadAllSync();
    }


    /**
     * 读取 Excel 文件并返回所有数据
     *
     * @param filePath Excel 文件路径
     * @param head     Excel 表头对应的实体类 Class
     * @param <T>      泛型类型
     * @return 包含 Excel 数据的 List
     */
    public static <T> List<T> read(String filePath, Class<T> head) {
        // 检查文件是否存在
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IllegalArgumentException("文件不存在: " + filePath);
        }

        // 创建一个列表存储读取的数据
        List<T> dataList = new ArrayList<>();

        // 使用 EasyExcel 读取文件
        EasyExcel.read(filePath, head, new AnalysisEventListener<T>() {
            @Override
            public void invoke(T data, AnalysisContext context) {
                // 每解析一行数据，将其添加到列表中
                dataList.add(data);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                // 所有数据解析完成后的操作（可选）
                System.out.println("Excel 文件读取完成！");
            }
        }).sheet().doRead();

        return dataList;
    }

    /**
     * 写入执行sheet
     *
     * @param filename
     * @param sheetName
     * @param head
     * @param data
     * @param <T>
     */
    public static <T> void write(String filename, String sheetName, Class<T> head, List<T> data) {
        EasyExcel.write(filename, head)
                .sheet(sheetName)
                .doWrite(() -> {
                    // 分页查询数据
                    return data;
                });
    }

    /**
     * 多sheet 写入
     *
     * @param filename
     * @param sheetNameList
     * @param sheetClassList
     * @param sheetDataLList
     */
    public static void write(String filename, List<String> sheetNameList, List<Class> sheetClassList, List<List> sheetDataLList) {
        // 指定文件
        try (ExcelWriter excelWriter = EasyExcel.write(filename).build()) {

            for (int i = 0; i < sheetNameList.size(); i++) {
                String sheetName = sheetNameList.get(i);
                Class tClass = sheetClassList.get(i);
                List ts = sheetDataLList.get(i);
                WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetName).head(tClass).build();
                excelWriter.write(ts, writeSheet);

            }
        }
    }

    /**
     * 读取csv
     *
     * @author wangShuai
     * @date 2025/4/15 周二
     */
    public static List<Map<String, String>> readCsv(String filePath) {
        List<Map<String, String>> dataList = new ArrayList<>();
        try (Reader reader = new FileReader(filePath);
             CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withHeader())) {
            for (CSVRecord csvRecord : csvParser) {
                Map<String, String> rowMap = new HashMap<>();
                for (String header : csvParser.getHeaderMap().keySet()) {
                    rowMap.put(header, csvRecord.get(header));
                }
                dataList.add(rowMap);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dataList;
    }


    /**
     * 将 List<Map<String, String>> 数据写入 CSV 文件
     *
     * @param filePath 要写入的 CSV 文件的路径
     * @param dataList 包含数据的 List<Map<String, String>>
     */
    public static void writeCsv(String filePath, List<Map<String, String>> dataList) {
        if (dataList.isEmpty()) {
            return;
        }
        // 获取表头
        List<String> headers = new ArrayList<>(dataList.get(0).keySet());
        try (Writer writer = new FileWriter(filePath);
             CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader(headers.toArray(new String[0])))) {
            for (Map<String, String> row : dataList) {
                List<String> rowData = new ArrayList<>();
                for (String header : headers) {
                    rowData.add(row.get(header));
                }
                csvPrinter.printRecord(rowData);
            }
            csvPrinter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}

